/*
 * property_base_.h
 *
 *  Created on: 2011-8-7
 *      Author: wangchao
 */

#ifndef PROPERTY__H_
#define PROPERTY__H_

#include <iostream>
#include <exception>
#include "property_base.h"

// not use this
template<typename Host, typename ValueType, typename Access = ReadWrite, typename StorePolicy = Storage>
class property_base_
{
public:
    property_base_()
    {
        C_ASSERT( IS_SAME_TYPE( Access, ReadOnly ) || IS_SAME_TYPE( Access, WriteOnly) || IS_SAME_TYPE( Access, ReadWrite ));
        C_ASSERT( IS_SAME_TYPE(StorePolicy, Storage ) || IS_SAME_TYPE( StorePolicy, PointToVar ));

        std::cout << "Host" << std::endl;
    }

    void set(const ValueType& value);
    const ValueType& get() const;
};

template<typename Host, typename ValueType>
class property_base_<Host, ValueType, ReadOnly, PointToVar>
{
    typedef void(Host::*Setter)(const ValueType &);
    typedef const ValueType &(Host::*Getter)() const;
public:
    property_base_()
            : _host(NULL), _getter(NULL)
    {
        std::cout << "Host ValueType, ReadWrite, PointToVar" << std::endl;
    }
    property_base_(Host* host, Getter getter)
            : _host(host), _getter(getter)
    {

    }

public:
    void bind(Host* host, Getter getter)
    {
        _host = host;
        _getter = getter;
    }
public:
    //void set(const ValueType& value);
    const ValueType& get() const
    {
        if (!_host)
        {
            throw std::exception();
        }
        return (_host->*_getter)();
    }
private:
    Host *_host;
    Getter _getter;
};
template<typename Host, typename ValueType>
class property_base_<Host, ValueType, WriteOnly, PointToVar>
{
    typedef void(Host::*Setter)(const ValueType &);
    typedef const ValueType &(Host::*Getter)() const;
public:
    property_base_()
            : _host(NULL), _setter(NULL)
    {
        std::cout << "Host ValueType, ReadWrite, PointToVar" << std::endl;
    }
    property_base_(Host* host, Setter setter, Getter getter)
            : _host(host), _setter(setter)
    {

    }
public:
    void bind(Host* host, Setter setter)
    {
        _host = host;
        _setter = setter;
    }
public:
    void set(const ValueType& value)
    {
        if (_host)
        {
            (_host->*_setter)(value);
        }
    }

    //const ValueType& get() const;
private:
    Host *_host;
    Setter _setter;
}
;
template<typename Host, typename ValueType>
class property_base_<Host, ValueType, ReadWrite, PointToVar>
{
    typedef void(Host::*Setter)(const ValueType &);
    typedef const ValueType &(Host::*Getter)() const;
public:
    property_base_()
            : _host(NULL), _setter(NULL), _getter(NULL)
    {
        std::cout << "Host ValueType, ReadWrite, PointToVar" << std::endl;
    }
    property_base_(Host* host, Setter setter, Getter getter)
            : _host(host), _setter(setter), _getter(getter)
    {

    }
public:
    void bind(Host* host, Setter setter, Getter getter)
    {
        _host = host;
        _setter = setter;
        _getter = getter;
    }
public:
    void set(const ValueType& value)
    {
        if (_host)
        {
            (_host->*_setter)(value);
        }
    }
    const ValueType& get() const
    {
        if (!_host)
        {
            throw std::exception();
        }
        return (_host->*_getter)();

    }
private:
    Host *_host;
    Setter _setter;
    Getter _getter;
};

template<typename Host, typename ValueType>
class property_base_<Host, ValueType, ReadOnly, Storage>
{
public:
    property_base_(const ValueType& value)
            : _value(value)
    {
        std::cout << "Host ValueType, ReadWrite, Storage" << std::endl;
    }
public:

public:
    // void set(const ValueType& value);
    const ValueType& get() const
    {
        return _value;
    }
private:
    ValueType _value;
};
template<typename Host, typename ValueType>
class property_base_<Host, ValueType, WriteOnly, Storage>
{
    typedef void (Host::*Callback)();
public:
    property_base_()
            : _host(NULL), _callback(NULL), _value(ValueType())
    {
        std::cout << "Host ValueType, WriteOnly, Storage" << std::endl;
    }
    property_base_(const ValueType& value)
            : _host(NULL), _callback(NULL), _value(value)
    {
        std::cout << "Host ValueType, ReadWrite, Storage" << std::endl;
    }
public:
    void bind(Host* host, Callback callback)
    {
        _host = host;
        _callback = callback;
    }
public:
    void set(const ValueType& value)
    {
        _value = value;
        if (_host)
        {
            (_host->*_callback)();
        }
    }
    //const ValueType& get() const;
private:
    Host *_host;
    Callback _callback;
    ValueType _value;
};
template<typename Host, typename ValueType>
class property_base_<Host, ValueType, ReadWrite, Storage>
{
    typedef void (Host::*Callback)();
public:
    property_base_()
            : _host(NULL), _callback(NULL), _value(ValueType())
    {

    }
    property_base_(const ValueType& value)
            : _host(NULL), _callback(NULL), _value(value)
    {
        std::cout << "Host ValueType, ReadWrite, Storage" << std::endl;
    }
public:
    void bind(Host* host, Callback callback)
    {
        _host = host;
        _callback = callback;
    }
public:
    void set(const ValueType& value)
    {
        _value = value;
        if (_host)
        {
            (_host->*_callback)();
        }
    }
    const ValueType& get() const
    {
        return _value;
    }

private:
    Host *_host;
    Callback _callback;
    ValueType _value;
};

template<typename Host, typename ValueType, typename Access = ReadWrite, typename StorePolicy = Storage>
class property_: public property_base_<Host, ValueType, Access, StorePolicy>
{
    typedef property_base_<Host, ValueType, Access, StorePolicy> base_class;
    typedef void(Host::*Setter)(const ValueType &);
    typedef const ValueType &(Host::*Getter)() const;
public:
    property_()
            : base_class()
    {

    }
    property_(const ValueType& value)
            : base_class(value)
    {

    }

    property_(Host* host, Setter setter, Getter getter)
            : base_class(host, setter, getter)
    {

    }
    property_(Host* host, Setter setter)
            : base_class(host, setter)
    {

    }
    property_(Host* host, Getter getter)
            : base_class(host, getter)
    {

    }
public:
    /** returns the property'setter value. Valid for readable properties.
     @return the property'setter value.
     */
    operator const ValueType&() const
    {
        return property_base_<Host, ValueType, Access, StorePolicy>::get();
    }

    /** returns the property'setter value. Valid for readable properties.
     @return the property'setter value.
     */
    const ValueType &operator ()() const
    {
        return property_base_<Host, ValueType, Access, StorePolicy>::get();
    }

    /** sets the property'setter value. Valid for writable properties.
     @param value new value.
     @return reference to this
     */
    property_<Host, ValueType, Access, StorePolicy> &operator =(const ValueType &value)
    {
        set(value);
        return *this;
    }
private:
    /** sets the property'setter value from another property. The other property
     might have a different access/storage policy.
     @param p property to copy the value of to this
     @return reference to this
     */
    template<typename Access1, typename Storage1>
    property_<Host, ValueType, Access, StorePolicy> &operator =(const property_<Host, ValueType, Access1, Storage1> &p)
    {
        set(p.get());
        return *this;
    }

private:
    //copy construction is not allowed
    property_(const property_<Host, ValueType, Access, StorePolicy> &p);
};
#endif /* PROPERTY__H_ */
